package com.virtualightning.mvvm.impl.task

import android.os.SystemClock
import kotlinx.coroutines.*
import java.io.Closeable
import java.lang.RuntimeException
import java.util.*
import kotlin.collections.HashSet

/**
 *  Anchor : Create by CimZzz
 *  Time : 2021/2/6 10:54:03
 *  Project : zxs-new
 *  任务管理器
 */
@Suppress("MemberVisibilityCanBePrivate", "unused", "RemoveExplicitTypeArguments")
class TaskManager(
    private val baseOnScope: CoroutineScope = GlobalScope,
    private val wrapperFactory: DeferredWrapperFactory? = null
) : Closeable {
    ///////////////////////////////////////////////////////////////////////////
    // Add by CimZzz on 2021/1/27 11:35 PM
    // 内部维持的一个 Deferred Array，用来主动取消 Deferred 任务
    ///////////////////////////////////////////////////////////////////////////
    private val deferredArray: HashMap<Any, DeferredWrapper<*>> by lazy { HashMap<Any, DeferredWrapper<*>>() }

    ///////////////////////////////////////////////////////////////////////////
    // Add by CimZzz on 2021/1/28 9:01 AM
    // 内部维持一个 Deferred Set，用来管理未指定 ReqCode 的 Deferred 的取消
    ///////////////////////////////////////////////////////////////////////////
    private val deferredSet: HashSet<DeferredWrapper<*>> by lazy { HashSet<DeferredWrapper<*>>() }

    ///////////////////////////////////////////////////////////////////////////
    // Add by CimZzz on 2021/11/5 10:47 上午
    // 判断当前 TaskManager 是否被销毁
    ///////////////////////////////////////////////////////////////////////////
    private var isClose: Boolean = false

    ///////////////////////////////////////////////////////////////////////////
    // Add by CimZzz on 2021/1/28 上午11:41
    // 调用一个异步结果请求
    // 这里可以是经过 Retrofit 封装过的 Deferred，也可以是数据库异步请求的 Deferred，总之结果
    // 应为 Deferred<T> 类型
    ///////////////////////////////////////////////////////////////////////////
    fun <T> callRequest(deferred: Deferred<T>, atLeastTime: Long = 0L) : DeferredWrapper<T> {
        return callRequest(-1, deferred, atLeastTime)
    }

    fun <T> callRequest(reqCode: Any, deferred: Deferred<T>, atLeastTime: Long = 0L) : DeferredWrapper<T> {
        if(isClose) {
            return wrapError(RuntimeException("task destroy"))
        }
        val deferredWrapper = wrapperFactory?.createWrapper<T>(deferred) ?: DeferredWrapper<T>(deferred)
        val wrapperDeferred = baseOnScope.async(Dispatchers.Main) {
            val beginTime = SystemClock.elapsedRealtime()
            if(deferred is ProgressDeferred<*>) {
                deferred.setProgressCallback {
                    deferredWrapper.progress(it)
                }
            }

            // 保证回调在主线程
            val result = kotlin.runCatching {
                if(deferred is BaseTask<*>) {
                    deferred.start()
                }
                deferred.await()
            }

            // 从 Deferred 容器中移除
            if(reqCode == -1) {
                deferredSet.remove(deferredWrapper)
            }
            else {
                deferredArray.remove(reqCode)
            }
            val endTime = SystemClock.elapsedRealtime()

            if(atLeastTime > 0L) {
                val distanceTime = endTime - beginTime
                if(distanceTime < atLeastTime) {
                    delay(atLeastTime - distanceTime)
                }
            }

            val taskResult = deferredWrapper.handleResult(result)

            val data = taskResult.data
            if(data != null) {
                deferredWrapper.success(data)
            }
            else {
                val exception = taskResult.exception
                deferredWrapper.failure(exception ?: RuntimeException("unknown exception"))
            }
        }

        deferredWrapper.wrapDeferred = wrapperDeferred

        if(reqCode == -1) {
            deferredSet.add(deferredWrapper)
        }
        else {
            deferredArray[reqCode]?.cancel()
            deferredArray[reqCode] = deferredWrapper
        }
        return deferredWrapper
    }

    ///////////////////////////////////////////////////////////////////////////
    // Add by CimZzz on 2021/2/6 上午11:06
    // 执行请求，如果该请求已经存在，则返回 Null
    ///////////////////////////////////////////////////////////////////////////
    fun <T> callIfNotExist(reqCode: Any, atLeastTime: Long = 0L, call: () -> Deferred<T>) : DeferredWrapper<T> {
        val deferredWrapper = deferredArray[reqCode]
        if(deferredWrapper != null) {
            // 注意，一定要管理好 ReqCode，防止类型强转换造成的问题
            @Suppress("UNCHECKED_CAST")
            return deferredWrapper as DeferredWrapper<T>
        }
        return callRequest(reqCode, call(), atLeastTime)
    }

    /**
     * 判断指定请求是否存在
     * @param reqCode Any 请求码
     * @return Boolean 如果存在返回 true
     */
    fun isRequestExist(reqCode: Any): Boolean {
        return deferredArray.containsKey(reqCode)
    }

    ///////////////////////////////////////////////////////////////////////////
    // Add by CimZzz on 2021/1/28 下午4:36
    // 取消请求
    // 通过请求 Id 取消
    ///////////////////////////////////////////////////////////////////////////
    fun cancelRequest(reqCode: Any) {
        deferredArray[reqCode]?.cancel() ?: return
        deferredArray.remove(reqCode)
    }

    ///////////////////////////////////////////////////////////////////////////
    // Add by CimZzz on 2021/3/12 上午10:22
    // 包装成功 DeferredWrapper
    ///////////////////////////////////////////////////////////////////////////
    fun <T> wrapSuccess(data: T): DeferredWrapper<T> {
        val wrapper = DeferredWrapper<T>()
        wrapper.success(data)
        return wrapper
    }

    ///////////////////////////////////////////////////////////////////////////
    // Add by CimZzz on 2021/3/12 上午10:24
    // 包装失败 DeferredWrapper
    ///////////////////////////////////////////////////////////////////////////
    fun <T> wrapError(error: Throwable): DeferredWrapper<T> {
        val wrapper = DeferredWrapper<T>()
        wrapper.failure(error)
        return wrapper
    }

    ///////////////////////////////////////////////////////////////////////////
    // Add by CimZzz on 2021/11/4 3:24 下午
    // 包装失败 DeferredWrapper
    ///////////////////////////////////////////////////////////////////////////
    fun <T> wrapError(error: String): DeferredWrapper<T> {
        val wrapper = DeferredWrapper<T>()
        wrapper.failure(RuntimeException(error))
        return wrapper
    }

    /**
     * 包装一个空的 DeferredWrapper
     * @return DeferredWrapper<T>
     */
    fun <T> empty(): DeferredWrapper<T> {
        return DeferredWrapper()
    }

    ///////////////////////////////////////////////////////////////////////////
    // Add by CimZzz on 2021/2/6 上午10:57
    // Closable 接口实现
    // 取消全部 Deferred 和 DisposableHandle
    ///////////////////////////////////////////////////////////////////////////
    override fun close() {
        isClose = true
        deferredSet.forEach {
            it.cancel()
        }

        deferredArray.values.forEach { task ->
            task.cancel()
        }
        deferredSet.clear()
        deferredArray.clear()
    }

    ///////////////////////////////////////////////////////////////////////////
    // Add by CimZzz on 2021/10/11 4:47 PM
    // 任务执行结果
    ///////////////////////////////////////////////////////////////////////////
    data class TaskResult<T> (
        val data: T?,
        val exception: Throwable?
    )

    ///////////////////////////////////////////////////////////////////////////
    // Add by CimZzz on 2021/6/6 8:02 PM
    // DeferredWrapper 工厂方法
    ///////////////////////////////////////////////////////////////////////////
    interface DeferredWrapperFactory {
        fun <T> createWrapper(mainDeferred: Deferred<T>) : DeferredWrapper<T>
    }

    ///////////////////////////////////////////////////////////////////////////
    // Add by CimZzz on 2021/1/28 上午11:42
    // 内部包装类
    ///////////////////////////////////////////////////////////////////////////
    open class DeferredWrapper<T> (
        private var mainDeferred: Deferred<*>? = null
    ): CompletableDeferred<T> by CompletableDeferred() {
        internal var wrapDeferred: Deferred<*>? = null
        internal var transformWrapper: Deferred<*>? = null
        internal var progressListener: MutableList<(Float) -> Unit>? = null
        internal var successListener: MutableList<(T) -> Unit>? = null
        internal var failureListener: MutableList<(Throwable) -> Unit>? = null
        internal var doneListener: MutableList<() -> Unit>? = null
        internal var progress: Float = 0f
        internal var successData: T? = null
        internal var failureException: Throwable? = null

        private fun finish() {
            successListener = null
            failureListener = null
            progressListener = null
            doneListener?.forEach {
                it()
            }
            doneListener = null
        }

        internal fun progress(progress: Float) {
            progressListener?.forEach {
                it.invoke(progress)
            }
            this.progress = progress
        }

        internal fun success(data: T) {
            successListener?.forEach {
                it.invoke(data)
            }
            successData = data
            finish()
            complete(data)
        }

        internal fun failure(error: Throwable) {
            failureListener?.forEach {
                it.invoke(error)
            }
            failureException = error
            finish()
            completeExceptionally(error)
        }


        override fun cancel(cause: CancellationException?) {
            transformWrapper = null
            transformWrapper?.cancel()
            finish()
            var tempWrapper: Deferred<*>? = wrapDeferred
            wrapDeferred = null
            tempWrapper?.cancel()
            tempWrapper = mainDeferred
            mainDeferred = null
            tempWrapper?.cancel()
        }

        ///////////////////////////////////////////////////////////////////////////
        // Add by CimZzz on 2021/11/12 11:28 上午
        // 监听进度回调
        ///////////////////////////////////////////////////////////////////////////
        fun onProgress(callback: (Float) -> Unit) : DeferredWrapper<T> {
            if(successData != null || failureException != null) {
                return this
            }
            if(isCancelled) {
                return this
            }
            callback(progress)
            if(progressListener == null) {
                progressListener = LinkedList()
            }
            progressListener?.add(callback)
            return this
        }

        ///////////////////////////////////////////////////////////////////////////
        // Add by CimZzz on 2021/1/28 上午11:56
        // 监听成功回调
        ///////////////////////////////////////////////////////////////////////////
        fun onSuccess(callback: (T) -> Unit) : DeferredWrapper<T> {
            if(successData != null || failureException != null) {
                val successData = successData
                if(successData != null) {
                    callback(successData)
                }
                return this
            }
            if(isCancelled) {
                return this
            }
            if(successListener == null) {
                successListener = LinkedList()
            }
            successListener?.add(callback)
            return this
        }

        ///////////////////////////////////////////////////////////////////////////
        // Add by CimZzz on 2021/1/28 上午11:59
        // 监听失败回调
        ///////////////////////////////////////////////////////////////////////////
        fun onFailure(callback: (Throwable) -> Unit) : DeferredWrapper<T> {
            if(successData != null || failureException != null) {
                val failureException = failureException
                if(failureException != null) {
                    callback(failureException)
                }
                return this
            }
            if(isCancelled) {
                return this
            }
            if(failureListener == null) {
                failureListener = LinkedList()
            }
            failureListener?.add(callback)
            return this
        }

        ///////////////////////////////////////////////////////////////////////////
        // Add by CimZzz on 2021/11/5 11:11 上午
        // 监听结束回调，在 cancel 时同样会触发该回调，所以该回调必定会被触发
        ///////////////////////////////////////////////////////////////////////////
        fun onDone(callback: () -> Unit) : DeferredWrapper<T> {
            if(isCancelled) {
                callback()
                return this
            }
            if(successData != null || failureException != null) {
                callback()
                return this
            }
            if(doneListener == null) {
                doneListener = LinkedList()
            }
            doneListener?.add(callback)
            return this
        }

        ///////////////////////////////////////////////////////////////////////////
        // Add by CimZzz on 2021/11/4 3:16 下午
        // 转换其他 Wrapper
        ///////////////////////////////////////////////////////////////////////////
        fun <R> transform(callback: (T) -> TaskResult<R>): DeferredWrapper<R> {
            val newWrapper = DeferredWrapper<R>(this)
            onSuccess {
                val result = callback(it)
                val data = result.data
                if(data != null) {
                    newWrapper.success(data)
                }
                else {
                    val exception = result.exception ?:
                        RuntimeException("unknown exception")
                    newWrapper.failure(exception)
                }
            }.onFailure {
                newWrapper.failure(it)
            }.onProgress {
                newWrapper.progress(it)
            }
            if(!isCompleted) {
                transformWrapper = newWrapper
            }
            return newWrapper
        }

        /**
         * 转换其他类型 Wrapper, 不考虑异常状态
         * @param callback Function1<T, R> 转换回调
         * @return DeferredWrapper<R> 其他类型 Wrapper
         */
        fun <R> castTo(callback: (T) -> R): DeferredWrapper<R> {
            return transform {
                TaskResult(callback(it), null)
            }
        }


        ///////////////////////////////////////////////////////////////////////////
        // Add by CimZzz on 2021/6/6 8:06 PM
        // 处理 Task 结果
        ///////////////////////////////////////////////////////////////////////////
        open fun handleResult(result: Result<T>) : TaskResult<T> {
            return TaskResult(
                result.getOrNull(),
                result.exceptionOrNull()
            )
        }
    }
}